package edu.osu.cse.c651.cryptochess;

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

/**
 * This class represents the GUI of our application; users interact with it to
 * play chess.
 * 
 * @author Team Pawned
 * 
 */
public class GameActivity extends Activity {

	/**
	 * Used to debug
	 */
	public static String TAG = "CryptoChess";

	/**
	 * The int ids of each square of the game board
	 */
	private int[][] gridIds;

	/**
	 * The user of this GUI and application
	 */
	private User user;

	/**
	 * The opponent of this player
	 */
	private User opponent;

	/**
	 * The color of this player (Color.WHITE or Color.BLACK)
	 */
	private Color color;

	/**
	 * The imageViews of each square of the game board
	 */
	private ImageView[][] tileViews;

	/**
	 * The controller of the model-view-controller paradigm. It's the
	 * intermediary between the model and the view.
	 */
	private BoardController boardController;

	/**
	 * The controller that communicates between the two users. It sends data
	 * after this User completes a move and receives data after the opponent
	 * completes a move.
	 */
	private ConnectionController connectionController;

	/**
	 * The SquareContainers that neatly package all the neccesary attributes of
	 * the game board GUI, for use by this class and the BoardController.
	 */
	public SquareContainer[][] squares;

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.game);
		gridIds = new int[8][8];
		squares = new SquareContainer[8][8];
		tileViews = new ImageView[8][8];
		init();
		Log.d(TAG, "Just set the Content View");

		user = (User) this.getIntent().getSerializableExtra("user");
		opponent = (User) this.getIntent().getSerializableExtra("opponent");
		color = (Color) this.getIntent().getSerializableExtra("color");
		InetAddress addr = (InetAddress) this.getIntent().getSerializableExtra(
				"ip");
		opponent.setIpAddress(addr);

		User darkUser;
		User lightUser;
		if (color == Color.WHITE) {
			lightUser = user;
			darkUser = opponent;
		} else {
			lightUser = opponent;
			darkUser = user;
		}

		View lightUserLayout = findViewById(R.id.gameLightUser);
		View darkUserLayout = findViewById(R.id.gameDarkUser);

		TextView lightUsername = (TextView) lightUserLayout
				.findViewById(R.id.textUsername);
		TextView lightRating = (TextView) lightUserLayout
				.findViewById(R.id.textRating);
		TextView lightWinLoss = (TextView) lightUserLayout
				.findViewById(R.id.textWinLoss);
		ImageView lightUserIcon = (ImageView) lightUserLayout
				.findViewById(R.id.imageUserIcon);

		lightUsername.setText("" + lightUser.getUsername());
		lightRating.setText("" + lightUser.getRating());
		lightWinLoss
				.setText("" + lightUser.getWins() + " W - "
						+ lightUser.getLosses() + " L - "
						+ lightUser.getDraws() + " D");
		lightUserIcon.setImageResource(lightUser.getUserIcon().getIconId());

		TextView darkUsername = (TextView) darkUserLayout
				.findViewById(R.id.textUsername);
		TextView darkRating = (TextView) darkUserLayout
				.findViewById(R.id.textRating);
		TextView darkWinLoss = (TextView) darkUserLayout
				.findViewById(R.id.textWinLoss);
		ImageView darkUserIcon = (ImageView) darkUserLayout
				.findViewById(R.id.imageUserIcon);

		darkUsername.setText("" + darkUser.getUsername());
		darkRating.setText("" + darkUser.getRating());
		darkWinLoss.setText("" + darkUser.getWins() + " W - "
				+ darkUser.getLosses() + " L - " + darkUser.getDraws() + " D");
		darkUserIcon.setImageResource(darkUser.getUserIcon().getIconId());

		((TextView) findViewById(R.id.titleText)).setText("You are " + color);

		Log.d(TAG, "About to create the Board Controller");

		boardController = new BoardController(this, new ChessBoard(),
				new Player(color));
		connectionController = new ConnectionController(this, opponent);
		connectionController.startReceive();
		/*
		 * if (color == Color.BLACK) { receiveBoard(); }
		 */
		Log.d(TAG, "About to create the Connection Controller");
	}

	/**
	 * Stores all of the square ids
	 */
	private void init() {
		gridIds[0][0] = R.id.tile_a1;
		gridIds[1][0] = R.id.tile_a2;
		gridIds[2][0] = R.id.tile_a3;
		gridIds[3][0] = R.id.tile_a4;
		gridIds[4][0] = R.id.tile_a5;
		gridIds[5][0] = R.id.tile_a6;
		gridIds[6][0] = R.id.tile_a7;
		gridIds[7][0] = R.id.tile_a8;
		gridIds[0][1] = R.id.tile_b1;
		gridIds[1][1] = R.id.tile_b2;
		gridIds[2][1] = R.id.tile_b3;
		gridIds[3][1] = R.id.tile_b4;
		gridIds[4][1] = R.id.tile_b5;
		gridIds[5][1] = R.id.tile_b6;
		gridIds[6][1] = R.id.tile_b7;
		gridIds[7][1] = R.id.tile_b8;
		gridIds[0][2] = R.id.tile_c1;
		gridIds[1][2] = R.id.tile_c2;
		gridIds[2][2] = R.id.tile_c3;
		gridIds[3][2] = R.id.tile_c4;
		gridIds[4][2] = R.id.tile_c5;
		gridIds[5][2] = R.id.tile_c6;
		gridIds[6][2] = R.id.tile_c7;
		gridIds[7][2] = R.id.tile_c8;
		gridIds[0][3] = R.id.tile_d1;
		gridIds[1][3] = R.id.tile_d2;
		gridIds[2][3] = R.id.tile_d3;
		gridIds[3][3] = R.id.tile_d4;
		gridIds[4][3] = R.id.tile_d5;
		gridIds[5][3] = R.id.tile_d6;
		gridIds[6][3] = R.id.tile_d7;
		gridIds[7][3] = R.id.tile_d8;
		gridIds[0][4] = R.id.tile_e1;
		gridIds[1][4] = R.id.tile_e2;
		gridIds[2][4] = R.id.tile_e3;
		gridIds[3][4] = R.id.tile_e4;
		gridIds[4][4] = R.id.tile_e5;
		gridIds[5][4] = R.id.tile_e6;
		gridIds[6][4] = R.id.tile_e7;
		gridIds[7][4] = R.id.tile_e8;
		gridIds[0][5] = R.id.tile_f1;
		gridIds[1][5] = R.id.tile_f2;
		gridIds[2][5] = R.id.tile_f3;
		gridIds[3][5] = R.id.tile_f4;
		gridIds[4][5] = R.id.tile_f5;
		gridIds[5][5] = R.id.tile_f6;
		gridIds[6][5] = R.id.tile_f7;
		gridIds[7][5] = R.id.tile_f8;
		gridIds[0][6] = R.id.tile_g1;
		gridIds[1][6] = R.id.tile_g2;
		gridIds[2][6] = R.id.tile_g3;
		gridIds[3][6] = R.id.tile_g4;
		gridIds[4][6] = R.id.tile_g5;
		gridIds[5][6] = R.id.tile_g6;
		gridIds[6][6] = R.id.tile_g7;
		gridIds[7][6] = R.id.tile_g8;
		gridIds[0][7] = R.id.tile_h1;
		gridIds[1][7] = R.id.tile_h2;
		gridIds[2][7] = R.id.tile_h3;
		gridIds[3][7] = R.id.tile_h4;
		gridIds[4][7] = R.id.tile_h5;
		gridIds[5][7] = R.id.tile_h6;
		gridIds[6][7] = R.id.tile_h7;
		gridIds[7][7] = R.id.tile_h8;

		for (int x = 0; x < 8; x++) {
			for (int y = 0; y < 8; y++) {
				tileViews[x][y] = (ImageView) findViewById(gridIds[x][y]);
				squares[x][y] = new SquareContainer(x, y, tileViews[x][y]);
			}
		}

		// ((ImageView)findViewById(R.id.tile_h8)).setOnClickListener(new
		// ChessImageListener());

		Log.d(TAG, "Finished setting listeners.");
	}

	/**
	 * Paints a square on the GUI with the supplied Piece
	 * 
	 * @param x
	 *            the row of the square on the GUI
	 * @param y
	 *            the column of the square on the GUI
	 * @param piece
	 *            the Piece to be painted (if null, a blank square is painted)
	 */
	public void paint(int x, int y, Piece piece) {
		if (piece == null) {
			((ImageView) findViewById(gridIds[x][y]))
					.setImageResource(R.drawable.tile_blank);
			return;
		}

		Color color = piece.color();
		PieceName name = piece.name();

		if (color == Color.WHITE) {
			switch (name) {
			case Pawn:
				((ImageView) findViewById(gridIds[x][y]))
						.setImageResource(R.drawable.tile_pawn_light);
				break;
			case Rook:
				((ImageView) findViewById(gridIds[x][y]))
						.setImageResource(R.drawable.tile_rook_light);
				break;
			case Knight:
				((ImageView) findViewById(gridIds[x][y]))
						.setImageResource(R.drawable.tile_knight_white);
				break;
			case Bishop:
				((ImageView) findViewById(gridIds[x][y]))
						.setImageResource(R.drawable.tile_bishop_light);
				break;
			case Queen:
				((ImageView) findViewById(gridIds[x][y]))
						.setImageResource(R.drawable.tile_queen_light);
				break;
			case King:
				((ImageView) findViewById(gridIds[x][y]))
						.setImageResource(R.drawable.tile_king_light);
				break;
			}
		} else {
			switch (name) {
			case Pawn:
				((ImageView) findViewById(gridIds[x][y]))
						.setImageResource(R.drawable.tile_pawn_dark);
				break;
			case Rook:
				((ImageView) findViewById(gridIds[x][y]))
						.setImageResource(R.drawable.tile_rook_dark);
				break;
			case Knight:
				((ImageView) findViewById(gridIds[x][y]))
						.setImageResource(R.drawable.tile_knight_dark);
				break;
			case Bishop:
				((ImageView) findViewById(gridIds[x][y]))
						.setImageResource(R.drawable.tile_bishop_dark);
				break;
			case Queen:
				((ImageView) findViewById(gridIds[x][y]))
						.setImageResource(R.drawable.tile_queen_dark);
				break;
			case King:
				((ImageView) findViewById(gridIds[x][y]))
						.setImageResource(R.drawable.tile_king_dark);
				break;
			}
		}
	}

	/**
	 * Adds a listener to a square on the GUI, where the SquareContainer
	 * represents this square
	 * 
	 * @param sq
	 *            the SquareContainer representing the square on the GUI
	 * @param listener
	 *            the listener to be added to the square
	 */
	public void addSquareListener(SquareContainer sq,
			ImageView.OnClickListener listener) {
		sq.getImage().setOnClickListener(listener);
	}

	/**
	 * Called if the game is over (checkmate or stalemate)
	 * 
	 * @throws IOException
	 * @throws UnknownHostException
	 */
	public void endGame() throws UnknownHostException, IOException {
		Socket socket = new Socket(opponent.getIpAddress().getHostName(), 54321);
		OutputStream cout = socket.getOutputStream();
		cout.write(("$").getBytes());
		Intent backToFindGame = new Intent(GameActivity.this,
				FindGameActivity.class);
		GameActivity.this.startActivity(backToFindGame);
	}

	/**
	 * Sends the board to the opponent; called after a move has been completed.
	 * 
	 * @param board
	 *            the board to be sent to the opponent
	 */
	public void sendBoard(ChessBoard board) {
		connectionController.send(board);
	}

	/**
	 * Called in the special circumstance that a pawn has reached the opposing
	 * end of the board, in which case a captured piece can be reinstated to the
	 * game in its place
	 * 
	 * @param capturedPieces
	 *            the possible pieces to be reinstated
	 * @return Piece the Piece chosen to be reinstated
	 */
	public Piece pawnReachedEnd_SwitchInPiece(ArrayList<Piece> capturedPieces) {
		if (capturedPieces.size() == 0) {
			return null;
		}
		final CharSequence[] cps = new CharSequence[capturedPieces.size()];
		for (int i = 0; i < capturedPieces.size(); i++) {
			String s = capturedPieces.get(i).name().toString();
			cps[i] = s.subSequence(0, s.length() - 1);
		}

		final Piece[] piece = new Piece[1];
		final Color color = capturedPieces.get(0).color();

		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setTitle("Pick a piece to switch out with your pawn");
		builder.setItems(cps, new DialogInterface.OnClickListener() {
			public void onClick(DialogInterface dialog, int item) {
				Piece p = null;
				if (cps[item].toString().equals("Pawn")) {
					p = new Pawn(color);
				} else if (cps[item].toString().equals("Rook")) {
					p = new Rook(color);
				} else if (cps[item].toString().equals("Knight")) {
					p = new Knight(color);
				} else if (cps[item].toString().equals("Bishop")) {
					p = new Bishop(color);
				} else if (cps[item].toString().equals("Queen")) {
					p = new Queen(color);
				}
				piece[0] = p;
			}
		});
		AlertDialog alert = builder.show();
		return piece[0];
	}

	/**
	 * Receive the board from the opponent; called after the opponent has
	 * completed a move.
	 * 
	 * @throws IOException
	 * @throws UnknownHostException
	 */
	public void receiveBoard(ChessBoard board) throws UnknownHostException,
			IOException {
		boardController.loadBoard(board);
	}
}